package com.example.steeringwheelseekbar


import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.boundsInParent
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import kotlin.math.atan2
import kotlin.math.sqrt

@Composable
fun SteerWheelBar(
    backgroundId: Int = R.drawable.ic_launcher_background, // 背景图id
    foregroundId: Int = R.drawable.test6, // 前景图片id
    foregroundFraction: Float = 0.5f, // 图片的大小
    clockwiseLimitAngle: Int = Int.MAX_VALUE, // 逆时针角度
    counterclockwiseLimitAngle: Int = Int.MIN_VALUE, // 顺时针角度
    listener: OnProgressChangedListener? = null // 角度改变的监听
) {
    val TAG = "SteerWheelBar"
    var dragOffset = Offset.Zero // 用于计算坐标点
    var currentDegrees: Float  // 当前角度
    var lastDegrees = 0f // 最后角度，用于经过档位去重判断
    var absoluteDegree = 0f // 绝对旋转角度
    var centerPoint = Offset.Zero // 中心点坐标
    var pressPoint = Offset.Zero // 按下点坐标
    var movePoint: Offset  // 移动点坐标
    var imageDegrees by remember { mutableFloatStateOf(0f) }// 当前角度

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .aspectRatio(1f)
            .onGloballyPositioned {
//                Log.e(TAG, "SteerWheelBar: ${it.boundsInParent()}")
                centerPoint = it.boundsInParent().center
            }
            .pointerInput(null) {
                detectDragGestures(
                    onDragStart = { position ->
                        dragOffset = position
                        pressPoint = getRelativelyCoordinate(position, centerPoint)
                        Log.e(TAG, "onDragStart:pressPoint $pressPoint")
                    },
                    onDragEnd = {
                        Log.e(TAG, "SteerWheelBar: onDragEnd")
                        movePoint = getRelativelyCoordinate(dragOffset, centerPoint)
                        absoluteDegree = lastDegrees
                    },
                    onDragCancel = {
                        // 好像走不到这里
                        Log.e(TAG, "SteerWheelBar: onDragCancel")
                    },
                    onDrag = { _, dragAmount ->
                        dragOffset += dragAmount
                        movePoint = getRelativelyCoordinate(dragOffset, centerPoint)
                        // 获取与按下点的相对夹角
                        val relativelyDegree = getRotationDegrees(pressPoint, movePoint)
                        // 当前角度
                        currentDegrees = absoluteDegree + relativelyDegree
                        if (lastDegrees != currentDegrees) {
                            /*此处的300是对每次转角差值的一个大致范围定义，这个差值大小与系统刷新率有关，刷新率越快差值越小，我用模拟器测试差值最大是340左右
                            这里用300取商，对于多圈后误差会更大，理论上4圈以后就会出错，因为4圈后会计算为第5圈，因为每次除法都会有60度超出*/
//                    Log.e(TAG, "lastDegrees: $lastDegrees currentDegrees: $currentDegrees")
                            currentDegrees += 360 * ((lastDegrees - currentDegrees) / 300).toInt()
                            if (currentDegrees <= (clockwiseLimitAngle + 0.4f) && currentDegrees >= (counterclockwiseLimitAngle - 0.4f)) {
                                imageDegrees = currentDegrees// 设置旋转角度
                                listener?.onProgressChanged(currentDegrees.toInt())
                            } else if (currentDegrees > clockwiseLimitAngle) {
                                if (currentDegrees < lastDegrees) { // 当手势往回转时直接清空累计的转角
                                    // 模拟手势抬起后又按下了的动作
                                    currentDegrees = clockwiseLimitAngle.toFloat()
                                    lastDegrees = currentDegrees
                                    absoluteDegree = lastDegrees
                                    pressPoint = getRelativelyCoordinate(dragOffset, centerPoint)
                                }
                            } else if (currentDegrees < counterclockwiseLimitAngle) {
                                if (currentDegrees > lastDegrees) { // 当手势往回转时直接清空累计的转角
                                    // 模拟手势抬起后又按下了的动作
                                    currentDegrees = counterclockwiseLimitAngle.toFloat()
                                    lastDegrees = currentDegrees
                                    absoluteDegree = lastDegrees
                                    pressPoint = getRelativelyCoordinate(dragOffset, centerPoint)
                                }
                            }
                            lastDegrees = currentDegrees
//                    Log.e(TAG, "--lastDegrees: $lastDegrees currentDegrees: $currentDegrees")
                        }
                    }
                )
            },
        contentAlignment = Alignment.Center
    ) {
        Image(
            painter = painterResource(id = backgroundId),
            contentScale = ContentScale.FillBounds,
            modifier = Modifier.fillMaxSize(), contentDescription = "background"
        )
        Image(
            painter = painterResource(id = foregroundId),
            modifier = Modifier
                .fillMaxSize(foregroundFraction)
                .rotate(imageDegrees), contentDescription = "foreground"
        )
    }
}

/**
 * 滑动接口
 */
fun interface OnProgressChangedListener {
    fun onProgressChanged(level: Int)
}

/**
 * @return 返回相对于按下点的旋转角度
 */
private fun getRotationDegrees(pressPoint: Offset, movePoint: Offset): Float {
    val pressPolar = getPolarCoordinate(pressPoint.x, pressPoint.y)
    val movePolar = getPolarCoordinate(movePoint.x, movePoint.y)
    // 相对转角
    var angle = (movePolar.second - pressPolar.second)
    if (angle < 0) angle += 360 // 将角度值调整到0-360的范围
    if (angle > 180) angle -= 360// 将角度值调整到-180-180的范围
    return angle
}

/**
 * 直角坐标转极坐标
 */
private fun getPolarCoordinate(x: Float, y: Float): Pair<Float, Float> {
    val radius = sqrt(x * x + y * y)
    var angle = atan2(y, x)
    // 将角度值调整到正确的范围
    if (angle < 0) {
        angle += 2f * Math.PI.toFloat()
    }
//        Log.e(TAG, "getPolarCoordinate: $radius ${toDegrees(angle.toDouble())}")
    return Pair(radius, Math.toDegrees(angle.toDouble()).toFloat())
}

// 坐标相对中心点平移
private fun getRelativelyCoordinate(point: Offset, centerPoint: Offset): Offset {
    return Offset(point.x - centerPoint.x, point.y - centerPoint.y)
}

@Preview
@Composable
fun SteerWheelBarPreview() {
    SteerWheelBar(R.drawable.ic_launcher_background)
}

